package com.zz.framework.core.base

import android.content.Context
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.zz.framework.core.annotation.BindViewModel
import com.zz.framework.core.common.ViewModelFactory
import com.zz.framework.core.ext.*
import com.zz.framework.R
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import java.lang.reflect.Field

/**
 * Copyright © 2019 zanezhao All rights reserved.
 * Created by zanezhao on 2019-11-11 11:29.
 * @author: zanezhao 1820022519@qq.com
 * @version: V1.0
 */
abstract class BaseViewModelBottomDialogFragment() : BottomSheetDialogFragment(), LifecycleObserver {
    private lateinit var viewModel: BaseViewModel<*>

    override fun onAttach(context: Context) {
        super.onAttach(context)
        //默认注册ViewModel
        initViewModel()
    }

    override fun onStart() {
        super.onStart()
        if (EventBus.getDefault().isRegistered(this).not()) {
            EventBus.getDefault().register(this)
        }
    }

    @Subscribe
    fun onMsg(e: Boolean) {

    }

    fun getBottomSheetBehavior(): BottomSheetBehavior<View>? {
        val view: View? = dialog?.findViewById(com.google.android.material.R.id.design_bottom_sheet)
        return view?.let { BottomSheetBehavior.from(view) }
    }

    fun setPeekHeight(peekHeight: Int) {
        if (peekHeight <= 0) {
            return
        }
        val bottomSheetBehavior = getBottomSheetBehavior()
        bottomSheetBehavior?.peekHeight = peekHeight
    }

    fun setMaxHeight(maxHeight: Int) {
        if (maxHeight <= 0) {
            return
        }
        dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, maxHeight)
        dialog?.window?.setGravity(Gravity.BOTTOM)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val containerView = inflater.inflate(R.layout.dialog_container_layout, container, false)
        containerView.findViewById<ViewGroup>(R.id.mContentLayout).let {
            it.addView(inflater.inflate(getLayoutResId(), it, false))
            initProgressLayout(it)
        }
        return containerView
    }

    var mProgressView: View? = null
    protected fun initProgressLayout(viewGroup: ViewGroup) {
        if (mProgressView == null) {
            mProgressView = layoutInflater.inflate(R.layout.loading_layout, viewGroup, false)
            mProgressView?.setOnClickListener({ _: View? -> })
            viewGroup?.addView(mProgressView)
            dismissProgress()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        setStyle(STYLE_NORMAL, R.style.AppBottomSheet)
        super.onCreate(savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        initView(view)
        initObserver()
        initData()
        super.onViewCreated(view, savedInstanceState)
    }

    /**
     *  根据 @BindViewModel 注解, 查找注解标示的变量（ViewModel）
     *  并且 创建 ViewModel 实例, 注入到变量中
     */
    private fun initViewModel() {
        javaClass.fields
            .filter { it.isAnnotationPresent(BindViewModel::class.java) }
            .forEach {
                it?.apply {
                    isAccessible = true
                    var annotation = this.getAnnotation(BindViewModel::class.java)
                    set(
                        this@BaseViewModelBottomDialogFragment,
                        getViewModel(annotation.isSingle, annotation.isRegisterError, this)
                    )
                }
            }

    }

    @Suppress("UNCHECKED_CAST")
    private fun getViewModel(isSingle: Boolean, isRegisterError: Boolean, field: Field): ViewModel {
//        var viewModelName: String? = field.genericType.typeName
        var viewModelName: String? = null
        if (viewModelName == null) {
            viewModelName = this.javaClass.getCanonicalName()
        }
        if (isSingle) viewModelName =
            "${this.javaClass.canonicalName}${this.toString()} :$viewModelName" else viewModelName
        val mViewModel: BaseViewModel<*> =
            ViewModelFactory.createViewModel(requireActivity(), viewModelName, field, isSingle)
        if (isRegisterError) {
            observeErrorLiveData(mViewModel)
        }
        observeFinishLiveData(mViewModel)
        viewModel = mViewModel
        return mViewModel
    }

    protected fun observeErrorLiveData(viewModel: BaseViewModel<*>) {
        viewModel?.errorLiveData?.observe(
            this,
            Observer { it?.let { error(it.code, it.message) } })
    }

    protected fun observeFinishLiveData(viewModel: BaseViewModel<*>) {
        viewModel?.finishedLiveData?.observe(this, Observer { it?.let { dismissProgress() } })
    }

    override fun onDestroyView() {
        EventBus.getDefault().unregister(this)
        removeViewModelObserver()
        super.onDestroyView()
    }

    private fun removeViewModelObserver() {
        if (this::viewModel.isInitialized) {
            viewModel?.let {
                lifecycle.removeObserver(it)
            }
        }
    }

    open fun initData() {

    }


    abstract fun getLayoutResId(): Int

    open fun initView(view: View) {

    }

    open fun initObserver() {
    }

    open fun error(code: Int, message: String) {
        dismissProgress()
        error(message)
    }

    open fun error(message: String) {
        if (TextUtils.equals(message, "closed")) {
            return
        }
        activity?.showToast(message)
    }


    fun getBaseActivity(): BaseUIActivity? {
        if (activity is BaseUIActivity) {
            return activity as BaseUIActivity
        } else {
            return null
        }
    }

    fun showProgress() {
        mProgressView?.visible()
    }

    fun dismissProgress() {
        mProgressView?.gone()
    }

    open fun show(activity: FragmentActivity?) {
        activity?.let {
            show(it.supportFragmentManager, tag)
        }
    }
}